<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!--[if lt IE 9]>
  <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<![endif]-->
<title>VIM 中文用户手册: 做大修改</title>
<link rel="stylesheet" href="vim-stylesheet.css" type="text/css" />
<link rel="canonical" href="https://yianwillis.github.io/vimcdoc/doc/usr_10.html" />
<script type="text/javascript" src="vimcdoc.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<nav id=banner>
<form action=tags.html target="tag_iframe">
  <input type="text" name="tag" id="tag" placeholder="标签搜索">
</form>
<iframe name="tag_iframe" src=""></iframe>
<a href="help.html">帮助总览</a> &middot;
<hr/>
<a href="quickref.html">快速参考</a> &middot;
<a href="index.html">命令索引</a> &middot;
<a href="eval.html#functions">函数列表</a> &middot;
<a href="quickref.html#option-list">选项列表</a> &middot;
<hr/>
<a href="usr_toc.html">用户手册</a> &middot;
<a href="help.html#reference_toc">参考手册</a> &middot;
</nav>

<header>
<h2>usr_10</h2>
</header>
<article id=outer>
<section class=inner>
<b class="vimtag"> <a name="usr_10.txt">usr_10.txt</a> </b>    适用于 Vim 9.0 版本。   最近更新: 2019年12月

                     <code class="vim">VIM 用户手册 - by Bram Moolenaar</code>
                                <code class="vim">译者</code>: Nek_in

                              做大修改


第四章我们已经介绍过做小修改的方法了。本章开始介绍如何重复多次修改和如何改动大
量的文字。这将包括使用可视模式处理一些文本块，还有使用一个外部程序去完成非常复
杂的功能。

 <a href="usr_10.html#10.1">10.1</a>   记录与回放命令
 <a href="usr_10.html#10.2">10.2</a>   替换
 <a href="usr_10.html#10.3">10.3</a>   命令范围
 <a href="usr_10.html#10.4">10.4</a>   global 命令
 <a href="usr_10.html#10.5">10.5</a>   可视列块模式
 <a href="usr_10.html#10.6">10.6</a>   读、写部分文件内容
 <a href="usr_10.html#10.7">10.7</a>   排版文本
 <a href="usr_10.html#10.8">10.8</a>   改变大小写
 <a href="usr_10.html#10.9">10.9</a>   使用外部程序

        下一章:  <a href="usr_11.html#usr_11.txt">usr_11.txt</a>   从崩溃中恢复
        前一章:  <a href="usr_09.html#usr_09.txt">usr_09.txt</a>   使用 GUI 版本
          目录:  <a href="usr_toc.html#usr_toc.txt">usr_toc.txt</a> 

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.1">10.1</a> </b>  记录与回放命令</h4>
"." 命令重复前一个修改操作。但如果你需要作一些更复杂的操作它就不行了。这时，记
录命令就变得很有效。这需要三个步骤:

1. "q<code class="special">{register}</code>" 命令启动一次击键记录，结果保存到 <code class="special">{register}</code> 指定的寄存器中。
   寄存器名可以用 a 到 z 中任一个字母表示。
2. 输入你的命令。
3. 键入 q (后面不用跟任何字符) 命令结束记录。

现在，你可以用 "@<code class="special">{register}</code>" 命令执行这个宏。

现在看看你可以怎么用这些命令。假设你有如下文件名列表:

<code class="section">        stdio.h </code>
<code class="section">        fcntl.h </code>
<code class="section">        unistd.h </code>
<code class="section">        stdlib.h </code>

    而你想把它变成这样:

<code class="section">        #include "stdio.h" </code>
<code class="section">        #include "fcntl.h" </code>
<code class="section">        #include "unistd.h" </code>
<code class="section">        #include "stdlib.h" </code>

先移动到第一行，接着执行如下命令:

        qa                      启动记录，并使用寄存器 a
        ^                       移到行首
        i#include "<code class="special">&lt;Esc&gt;</code>        在行首输入 #include "
        $                       移到行末
        a"<code class="special">&lt;Esc&gt;</code>                 在行末加上双引号 (")
        j                       移到下一行
        q                       结束记录

现在，你已经完成一次复杂的修改了。你可以通过重复三次 "@a" 完成余下的修改。

"@a" 命令可以通过计数前缀修饰，使操作重复指定的次数。在本例中，你可以输入:

<code class="example">        3@a</code>
<code class="example"></code>
<code class="example"></code>
移 动 并 执 行

你可能有多个地方需要修改。只要把光标移动到相应的位置并输入 "@a" 命令即可。如果
你已经执行过一次，你可以用 "@@" 完成这个操作，这更容易输入一些。例如，你上次使
用 "@b" 命令引用了寄存器 b，下一个 "@@" 命令将使用寄存器 b。
    如果你对回放命令和 "." 命令作一个比较，你会发现几个区别。首先，"." 只能重
复一次改动。而在上例中，"@a" 可以重复多次改动，还能够执行移动操作。第二，"."
只能记住最后一次变更操作。而寄存器执行命令允许你记录任何操作并使用像 "@a" 这样
的命令回放这些被记录的操作。最后，你可以使用 26 个寄存器，因此，你可以记录多达
26 个命令序列。


使 用 寄 存 器

用来记录操作的寄存器与你用来拷贝文本的寄存器是相同的。这允许你混合记录操作和其
它命令来操作这些寄存器。
    假设你在寄存器 n 中记录了一些命令。当你通过 "@n" 执行这些命令时，你发现这
些命令有些问题。这时你可以重新录一次，但这样你可能还会犯其它错误。其实，你可以
使用如下窍门:

        G                       移到行尾
        o<code class="special">&lt;Esc&gt;</code>                  建立一个空行
        "np                     拷贝 n 寄存器中的文本，你的命令将被拷到整个文
                                件的结尾
        <code class="special">{edits}</code>                 像修改普通文本一样修改这些命令
        0                       回到行首
        "ny$                    把正确的命令拷贝回 n 寄存器
        dd                      删除临时行

现在你可以通过 "@n" 命令执行正确的命令序列了。(如果你记录的命令包括换行符，请
调整上面例子中最后两行的操作来包括所有的行。)

追 加 寄 存 器

到此为止，我们一直使用小写的寄存器名。要附加命令到一个寄存器中，可以使用大写的
寄存器名。
    假设你在寄存器 c 中已经记录了一个修改一个单词的命令。它可以正常工作，但现
在你需要附加一个搜索命令以便找到下一个单词来修改。这可以通过如下命令来完成:

<code class="example">        qC/word&lt;Enter&gt;q</code>
<code class="example"></code>
启动 "qC" 命令可以对 c 寄存器追加记录。由此可见，记录到一个大写寄存器表示附加
命令到对应的小写寄存器。

这种方法在宏记录，拷贝和删除命令中都有效。例如，你需要把选择一些行到一个寄存器
中，可以先这样拷贝第一行:

<code class="example">        "aY</code>
<code class="example"></code>
然后移到下一个要拷贝的地方，执行:

<code class="example">        "AY</code>
<code class="example"></code>
如此类推。这样在寄存器 a 中就会包括所有你要拷贝的所有行。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.2">10.2</a> </b>  替换                                            <b class="vimtag"> <a name="find-replace">find-replace</a> </b></h4>
":substitute" 命令使你可以在连续的行中执行字符串替换。下面是这个命令的一般形
式:

<code class="example">        :[range]substitute/from/to/[flags]</code>
<code class="example"></code>
这个命令把 <code class="special">[range]</code> 指定范围中的字符串 "from" 修改为字符串 "to"。例如，你可以把
连续几行中的 "Professor" 改为 "Teacher"，方法是:

<code class="example">        :%substitute/Professor/Teacher/</code>

        <code class="note">备注</code>:
        很少人会把整个 ":substitute" 命令完整敲下来。通常，使用命令的缩写形式
        ":s" 就行了。下文我们将使用这个缩写形式。

命令前面的 "%" 表示命令作用于全部行。如果不指定行范围，":s" 命令只作用在当前行
上。 <a href="usr_10.html#10.3">10.3</a>  将对 "行范围" 作深入的介绍。

默认情况下，":substitute" 命令只对某一行中的第一个匹配点起作用。例如，前面例子
中会把行:

<code class="section">        Professor Smith criticized Professor Johnson today. </code>

修改成:

<code class="section">        Teacher Smith criticized Professor Johnson today. </code>

要对行中所有匹配点起作用，你需要加一个 g (global，全局) 标记。下面命令:

<code class="example">        :%s/Professor/Teacher/g</code>
<code class="example"></code>
对上面例子中的句子的作用效果如下:

<code class="section">        Teacher Smith criticized Teacher Johnson today. </code>

":s" 命令还支持其它一些标志位，包括 "p" (print，打印)，用于在命令执行的时候打
印出最后一个被修改的行。还有 "c" (confirm，确认) 标记会在每次替换前向你询问是
否需要替换。执行如下命令:

<code class="example">        :%s/Professor/Teacher/c</code>
<code class="example"></code>
Vim 找到第一个匹配点的时候会向你提示如下:

<code class="example">        replace with Teacher (y/n/a/q/l/^E/^Y)?</code>
<code class="example"></code>
(中文翻译如下:

<code class="example">        替换为 Teacher 么 (y/n/a/q/l/^E/^Y)?</code>

)

这种时候，你可以输入如下回答中的一个:

        y               Yes，是；执行替换
        n               No，否；跳过
        a               All，全部；对剩下的匹配点全部执行替换，不需要再确认
        q               Quit，退出；不再执行任何替换
        l               Last，最后；替换完当前匹配点后退出
        <code class="keystroke">CTRL-E</code>          向上滚动一行
        <code class="keystroke">CTRL-Y</code>          向下滚动一行


":s" 命令中的 "from" 部分实际上是一个 "匹配模式" (还记得吗？这是我们前面给
pattern 起的名字<code class="vim">译者</code>)，这与查找命令一样。例如， 要替换行首的 "the" 可以这样
写:

<code class="example">        :s/^the/these/</code>
<code class="example"></code>
如果你要在 "from" 或者 "to" 中使用正斜杠，你需要在前面加上一个反斜杠。更简单的
方法是用加号代替正斜杠。例如:

<code class="example">        :s+one/two+one or two+</code>
<code class="example"></code>
</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.3">10.3</a> </b>  命令范围</h4>
":substitute" 命令和很多其它的 ":" 命令一样，可以作用于选中的一些行。这称为一
个 "范围"。
    最简单的范围表达形式是 "<code class="special">{number}</code>,<code class="special">{number}</code>"。例如:

<code class="example">        :1,5s/this/that/g</code>
<code class="example"></code>
这会在 1 到 5 行上执行替换命令。(包括第 5 行)。"范围" 总是放在一个命令的前面。

如果只用一个数值，表示某个指定的行:

<code class="example">        :54s/President/Fool/</code>
<code class="example"></code>
有些命令在不指定范围的时候作用于整个文件。要让它只作用于当前行可以用当前行范围
标识 "."。":write" 命令就是这样: 不指定范围的时候，它写入整个文件，如果要仅写
入当前行，可以这样:

<code class="example">        :.write otherfile</code>
<code class="example"></code>
文件的第一行行号总是 1，最后一行又是多少呢？"$" 字符用于解决这个问题。例如，要
修改当前行到文件末的全部内容，可以这样:

<code class="example">        :.,$s/yes/no/</code>
<code class="example"></code>
我们前面使用的 "%" 就是 "1,$" 的缩写形式，表示从文件首到文件末。


在 范 围 中 使 用 模 式

假设你正在编辑一本书中的一章，并且想把所有的 "grey" 修改成 "gray"。但你只想修
改这一章，不想影响其它的章节。另外，你知道每章的开头的标志是行首的单词为
"Chapter"。下面的命令会对你有帮助:

<code class="example">        :?^Chapter?,/^Chapter/s=grey=gray=g</code>
<code class="example"></code>
你可以看到这里使用了两个查找命令。第一个是 "?^Chapter?"，用于查找前一个行首的
"Chapter"，就是说 "?pattern?" 用于向前查找。同样，"/^Chapter/" 用于向后查找下
一章。
    为了避免斜杠使用的混淆，在这种情况下，"=" 字符用于代替斜杠。使用斜杠或使用
其它字符其实也是可以的。


加 减 号

上面的方案其实还是有问题的: 如果下一章的标题行中包括 "grey"，这个 "grey" 也会
被替换掉。如果你正好想这样就最好，可是正好你不想呢？这个时候你需要指定一个偏
移。
    要查找一个模式，并且使用它的前一行，需要这样:

<code class="example">        /Chapter/-1</code>
<code class="example"></code>
你可以用任意数值代替命令中的 1。要定位匹配点下的第二行，要这样:

<code class="example">        /Chapter/+2</code>
<code class="example"></code>
偏移还可以用于其它范围指定符。看一下下面这个例子:

<code class="example">        :.+3,$-5</code>
<code class="example"></code>
这指定当前行下面第三行到文件末倒数第五行的范围。


使 用 标 记

除了指定行号，(这需要记住并把它敲出来)，你还可以使用标记。
    在前面的例子中，你可以用标记指出第三章的位置。例如，用 "mt" 标记开头，再用
"mb" 标记结尾。然后你就可以用标记表示一个范围 (包括标记的那一行):

<code class="example">        :'t,'b</code>
<code class="example"></code>
<code class="example"></code>
可 视 模 式 和 范 围

你可以在可视模式中选中一些行。如果你现在输入 ":" 启动冒号命令模式，你会看到:

<code class="example">        :'&lt;,'&gt;</code>
<code class="example"></code>
现在，你可以输入剩下的命令，这个命令的作用范围就是可视模式中指定的范围。

        <code class="note">备注</code>:
        如果使用可视模式选中行的一部分，或者用 <code class="keystroke">CTRL-V</code> 选中一个文本列块，然后执
        行冒号命令，命令仍作用于整行，而不只是选中的范围。这可能会在以后的版本
        中修正。

'&lt; 和 '&gt; 实际上是标记，分别标识可视模式的开始和结尾。这个标记一直有效，直到选
中了其它的范围为止。你还可以用标记跳转命令 "'&lt;" 跳转到选中文本的开始处。你还可
以把这个标记和其它标记混合，例如:

<code class="example">        :'&gt;,$</code>
<code class="example"></code>
这表示从选中部分的结尾到文件末。


指 定 行 数

如果你知道要修改多少行，你可以先输入一个数值再输入冒号。例如，如果你输入
"5:"，你会得到:

<code class="example">        :.,.+4</code>
<code class="example"></code>
现在你可以继续你的命令，这个命令将作用于当前行及其后 4 行。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.4">10.4</a> </b>  global 命令</h4>
":global" 命令是 Vim 中一个更强大的命令 (之一)。它允许你找到一个匹配点并且在那
里执行一个命令。它的一般形式是:

<code class="example">        :[range]global/{pattern}/{command}</code>
<code class="example"></code>
这有点像 ":substitute" 命令。只是它不替换文本，而是执行 <code class="special">{command}</code> 指定的命令。

        <code class="note">备注</code>:
        global 中执行的命令只能是冒号命令。普通模式命令不能在这里使用。如果需
        要，可以使用  <a href="various.html#:normal">:normal</a>  命令。

假设你要把 "foobar" 修改为 "barfoo"，但只需要修改 C++ 风格的注释中的内容。这种
注释以 "//" 开头。所以可以使用如下命令:

<code class="example">        :g+//+s/foobar/barfoo/g</code>
<code class="example"></code>
这个命令用 ":g" 开头，这是 ":global" 的缩写形式，就像 ":s" 是 ":substitute" 的
缩写形式一样。然后是一个匹配模式，由于模式中包括正斜杠，我们用加号作分隔符，后
面是一个把 "foobar" 替换成 "barfoo" 的替换命令。
    全局命令的默认范围是整个文件，所以这个例子中没有指定范围。这一点与
":substitute" 是不同的。后者只作用于一行。
    这个命令并非完美。因为 "//" 可能出现在一行的中间，但替换命令会把前后的匹配
点都替换了。

像 ":substitute" 一样，这里也可以使用各种各样的匹配模式。当你从后面的章节中学
会更多的关于模式的知识，它们都可以用在这里。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.5">10.5</a> </b>  可视列块模式</h4>
<code class="keystroke">CTRL-V</code> 命令可以选中一个矩形文本块。有几个命令是专门用来处理这个文本块的。

在可视列块模式中，"$" 命令有些特别。当最后一个移动命令是 "$" 时，整个可视列块
将被扩展到每一行的行尾。这种状态在你使用垂直移动命令的时候一直被保持，直到你使
用水平移动命令为止。就是说，用 "j" 命令会保持这种状态，而 "h" 会退出。


插 入 文 本

"I<code class="special">{string}</code><code class="special">&lt;Esc&gt;</code>" 命令把 <code class="special">{string}</code> 插到可视列块的每一行的左边。你用 <code class="keystroke">CTRL-V</code> 进入
可视列块模式，然后移动光标定义一个列块。接着输入 I 进入插入模式，并随后输入文
本。这时，你输入的内容只出现在第一行。
    然后你输入 <code class="special">&lt;Esc&gt;</code> 结束输入，刚才输入的字符串将神奇地出现在每一行的可视区的
左边。例如:

<code class="section">        include one </code>
<code class="section">        include two </code>
<code class="section">        include three </code>
<code class="section">        include four </code>

把光标移到第一行 "one" 的 "o"上，输入 <code class="keystroke">CTRL-V</code>。然后用 "3j" 向下移动到 "four"。
现在你选中了四行的一个方块。接着输入:

<code class="example">        Imain.&lt;Esc&gt;</code>
<code class="example"></code>
结果将是:

<code class="section">        include main.one </code>
<code class="section">        include main.two </code>
<code class="section">        include main.three </code>
<code class="section">        include main.four </code>

如果选中的块经过一个短行，并且这行没有任何内容包括在可视列块中，则新的文本不会
被插入到该行中。例如，对于下面的例子，用可视列块选中第一和第三行的 "long"，这
样第二行的文本将不会被包括在可视列块中:

<code class="section">        This is a long line </code>
<code class="section">        short </code>
<code class="section">        Any other long line </code>

                  ^^^^ 用可视列块选中的部分

现在输入 "Ivery <code class="special">&lt;esc&gt;</code>"。结果将是:

<code class="section">        This is a very long line </code>
<code class="section">        short </code>
<code class="section">        Any other very long line </code>

可以<code class="note">注意</code>到，第二行中没有插入任何文本。

如果插入的文本中包括一个新行，则 "I" 命令的效果与普通插入语句一样，只影响块的
第一行。

"A" 命令的效果与 "I" 命令一样，只是把文字插入可视列块的右边，而且在短行中会插
入文字。这样，你有在短行中插入文字与否的不同选择。
    "A" 在如下情况会有一些特别: 选中一个可视列块然后用 "$" 命令使可视列块扩展
到行尾。然后用 "A" 命令插入文本，文件将被插入到 "每一行" 的行尾。
    还是用上面的例子，在选中可视列块后输入 "$A XXX<code class="special">&lt;Esc&gt;</code>"，结果将是:

<code class="section">        This is a long line XXX </code>
<code class="section">        short XXX </code>
<code class="section">        Any other long line XXX </code>

出现这个效果完全是 "$" 命令的作用，Vim 能记住这个命令，如果你用移动命令选中相
同的可视列块，是不会有这样的效果的。


修 改 文 本

可视列块中的 "c" 命令会删除整个可视列块并转入 "插入" 模式，使你可以开始文本，
这些文本会被插入可视列块经过的每一行。
    在上面的例子中，如果仍选中包括所有 "long" 的一个可视列块，然后输入
"c_LONG_<code class="special">&lt;Esc&gt;</code>"，结果会变成:

<code class="section">        This is a _LONG_ line </code>
<code class="section">        short </code>
<code class="section">        Any other _LONG_ line </code>

与 "I" 命令一样，短行不会发生变化。而且在插入的过程中，你不能断行。

"C" 命令从块的左边界开始删除所有行的后半段，然后状态切换到 "插入" 模式让你输
入文本。新的文本被插入到每一行的末尾。
    在上面的例子中，如果命令改为 "Cnew text<code class="special">&lt;Esc&gt;</code>"，你将获得这样的结果:

<code class="section">        This is a new text </code>
<code class="section">        short </code>
<code class="section">        Any other new text </code>

可以<code class="note">注意</code>到，尽管只有 "long" 被选中，它后面的内容也被删除了。所以在这种情况下，
块的左边界才是有意义的。
    同样，没有包括在块中的行不会受影响。

还有一些命令只影响被选中的字符:

        ~       交换大小写     (a -&gt; A 而 A -&gt; a)
        U       转换成大写     (a -&gt; A 而 A -&gt; A)
        u       转换成小写     (a -&gt; a 而 A -&gt; a)


以 一 个 字 符 填 充

要以某一个字符完全填充整个块，可以使用 "r" 命令。再次选中上例中的文本，然后键
入 "rx":

<code class="section">        This is a xxxx line </code>
<code class="section">        short </code>
<code class="section">        Any other xxxx line </code>


        <code class="note">备注</code>:
        如果你要在可视列块中包括行尾之后的字符，请参考 25 章的 <a href="options.html#'virtualedit'">'virtualedit'</a>
        特性。


平 移

"&gt;" 命令把选中的文档向右移动一个 "平移单位"，中间用空白填充。平移的起始点是可
视列块的左边界。
    还是用上面的例子，"&gt;" 命令会导致如下结果:

<code class="section">        This is a         long line </code>
<code class="section">        short </code>
<code class="section">        Any other         long line </code>

平移的距离由 <a href="options.html#'shiftwidth'">'shiftwidth'</a> 选项定义。例如，要每次平移 4 个空格，可以用这个命
令:

<code class="example">        :set shiftwidth=4</code>
<code class="example"></code>
"&lt;" 命令向左移动一个 "平移单位"，但能移动的距离是有限的，因为它左边的不是空白
字符的字符会挡住它，这时它移到尽头就不再移动。


连 接 若 干 行

"J" 命令连接被选中的行。也就是删除所有的换行符。其实不只是换行符，行前后的多余
空白字符会一起被删除而全部用一个空格取代。如果行尾刚好是句尾，就插入两个空格
(参见 <a href="options.html#'joinspaces'">'joinspaces'</a> 选项)
    还是用那个我们已经非常熟悉的例子，这回的结果将是:

<code class="section">        This is a long line short Any other long line </code>

"J" 命令其实不关心选中了哪些字符，只关心块涉及到哪些行。所以可视列块的效果与
"v" 和 "V" 的效果是完全一样的。

如果你不想改变那些空白字符，可以使用 "gJ" 命令。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.6">10.6</a> </b>  读、写文件的一部分</h4>
当你在写一封 e-mail，你可能想包括另一个文件。这可以通过 ":read <code class="special">{filename}</code>" 命
令达到目的。这些文本将被插入到光标的下面。
    我们用下面的文本作试验:

<code class="section">        Hi John, </code>
<code class="section">        Here is the diff that fixes the bug: </code>
<code class="section">        Bye, Pierre. </code>

把光标移到第二行然后输入:

<code class="example">        :read patch</code>
<code class="example"></code>
名叫 "patch" 的文件将被插入，成为下面这个样子:

<code class="section">        Hi John, </code>
<code class="section">        Here is the diff that fixes the bug: </code>
<code class="section">        2c2 </code>
<code class="section">        &lt;       for (i = 0; i &lt;= length; ++i) </code>
<code class="section">        --- </code>
<code class="section">        &gt;       for (i = 0; i &lt; length; ++i) </code>
<code class="section">        Bye, Pierre. </code>

":read" 支持范围前缀。文件将被插入到范围指定的最后一行的下面。所以
":$r patch" 会把 "patch" 文件插入到当前文件的最后。
    如果要插入到文件的最前面怎么办？你可以把文本插入到第 0 行，这一行实际上是
不存在的。在普通的命令的范围中如果你用这个行号会出错，但在 "read" 命令中就可
以:

<code class="example">        :0read patch</code>
<code class="example"></code>
这个命令把 "patch" 文件插入到全文的最前面。


保 存 部 分 行

要把一部分行写入到文件，可以使用 ":write" 命令。在没有指定范围的时候它写入全
文，而指定范围的时候它只写入范围指定的行:

<code class="example">        :.,$write tempo</code>
<code class="example"></code>
这个命令写入当前位置到文件末的全部行到文件 "tempo" 中。如果这个文件已经存在，
你会被提示错误。Vim 不会让你直接写入到一个已存在的文件。如果你知道你在干什么而
且确实想这样做，就加一个叹号:

<code class="example">        :.,$write! tempo</code>
<code class="example"></code>
小 心: "!" 必须紧跟着 ":write"，中间不能留有空格。否则这将变成一个过滤器命令，
这种命令我们在本章的后面会介绍。


添 加 内 容 到 文 件 中

本章开始的时候介绍了怎样把文本添加到寄存器中。你可以对文件作同样的操作。例如，
把当前行写入文件:

<code class="example">        :.write collection</code>
<code class="example"></code>
然后移到下一个位置，输入:

<code class="example">        :.write &gt;&gt;collection</code>
<code class="example"></code>
"&gt;&gt;" 通知 Vim 把内容添加到文件 "collection" 的后面。你可以重复这个操作，直到获
得全部你需要收集的文本。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.7">10.7</a> </b>  排版文本</h4>
在你输入纯文本时，自动换行自然会是比较吸引的功能。要实现这个功能，可以设置
<a href="options.html#'textwidth'">'textwidth'</a> 选项:

<code class="example">        :set textwidth=72</code>
<code class="example"></code>
你可能还记得在示例 vimrc 文件中，这个命令被用于所有的文本文件。所以如果你使用
的是那个配置文件，实际上你已经设置这个选项了。检查一下该选项的值:

<code class="example">        :set textwidth</code>
<code class="example"></code>
现在每行达到 72 个字符就会自动换行。但如果你只是在行中间输入或者删除一些东西，
这个功能就无效了。Vim 不会自动排版这些文本。
    要让 Vim 排版当前的段落:

<code class="example">        gqap</code>
<code class="example"></code>
这个命令用 "gq" 开始，作为操作符，然后跟着 "ap"，作为文本对象，该对象表示 "一
段" (a paragraph)。"一段" 与下一段的分割符是一个空行。

        <code class="note">备注</code>:
        只包括空白字符的空白行不能分割 "一段"。这很不容易分辨。

除了用 "ap"，你还可以使用其它 "动作" 或者 "文本对象"。如果你的段落分割正确，你
可以用下面命令排版整个文档:

<code class="example">        gggqG</code>
<code class="example"></code>
"gg" 跳转到第一行，"gq" 是排版操作符，而 "G" 是跳转到文尾的 "动作" 命令。

如果你没有清楚地区分段落。你可以只排版你手动选中的行。先移到你要排版的行，执行
"gqj"。这会排版当前行和下面一行。如果当前行太短，下面一行会补上来，否则多余的
部分会移到下面一行。现在你可以用 "." 命令重复这个操作，直到排版完所有的文本。

</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.8">10.8</a> </b>  改变大小写</h4>
你手头有一个分节标题全部是小写的。你想把全部 "section" 改成大写的。这可以用
"gU" 操作符。先在第一列执行:

<code class="example">                             gUw</code>
        section header      ----&gt;      SECTION header

"gu" 的作用正好相反:

<code class="example">                             guw</code>
        SECTION header      ----&gt;      section header

你还可以用 "g~" 来交换大小写。所有这些命令都是操作符，所以它们可以用于 "动作"
命令，文本对象和可视模式。
    要让一个操作符作用于当前行，可以执行这个操作符两次。例如，"d" 是删除操作
符，所以删除一行就是 "dd"。相似地，"gugu" 使整一行变成小写。这可以缩成 "guu"。
"gUgU" 可以缩成 "gUU" 而 "g~g~" 则是 "g~~"。例如:

<code class="example">                                g~~</code>
<code class="section">        Some GIRLS have Fun    ----&gt;   sOME girls HAVE fUN </code>


</section><hr class="doubleline" /><section class=inner>
<h4><b class="vimtag"> <a name="10.9">10.9</a> </b>  使用外部程序</h4>
Vim 有一套功能非常强大的命令，可以完成所有功能。但有些东西外部命令能够完成得更
好或者更快。
    命令 "!<code class="special">{motion}</code><code class="special">{program}</code>" 用一个外部程序对一个文本块进行过滤。换句话说，它
用一个文本块作为输入，执行一个由 <code class="special">{program}</code> 指定的外部命令，然后用该程序的输出
替代选中的文本块。
    如果你不熟悉 UNIX 的过滤程序，上面的描述可以说是比较糟糕的。我们这里举个例
子来说明一下。sort 命令能对一个文件排序。如果你执行下面的命令，未排序的文件
input.txt 会被排序并写入 output.txt。(这在 UNIX 和 Microsoft Windows 上都有效)

<code class="example">        sort &lt;input.txt &gt;output.txt</code>
<code class="example"></code>
现在在 Vim 中完成相同的功能。假设你要对 1 到 5 行排序。你可以先把光标定位在第
一行，然后你执行下面的命令:

<code class="example">        !5G</code>
<code class="example"></code>
"!" 告诉 Vim 你正在执行一个过滤操作。然后 Vim 编辑器等待一个 "动作" 命令来告诉
它要过滤哪部分文本。"5G" 命令告诉 Vim 移到第 5 行。于是，Vim 知道要处理的是第
1 行 (当前行) 到第 5 行间的内容。
    由于在执行一个过滤命令，光标被 Vim 移到了屏幕的底部，并显示一个 "!" 作提示
符。现在你可以输入过滤程序的名字，在本例中就是 "sort" 了。因此，你整个命令将
是:

<code class="example">        !5Gsort&lt;Enter&gt;</code>
<code class="example"></code>
这个命令的结果是 sort 程序用前 5 行作为输入执行，程序的输出替换了原来的 5 行。

        line 55                       line 11
        line 33                       line 22
        line 11         --&gt;           line 33
        line 22                       line 44
        line 44                       line 55
        last line                     last line

"!!" 命令用于对当前行执行过滤命令。在 Unix 上，"date" 命令能打印当前的时间和日
期，所以，"!!date<code class="special">&lt;Enter&gt;</code>" 用 "date" 的输出代替当前行。这在为文件加入时间戳的时
候非常有用。


如 果 命 令 不 执 行 怎 么 办

启动一个外壳，发送一个命令并捕获它的输出，这需要 Vim 知道这个外壳程序是怎么工
作的。如果你要使用过滤程序，你最好需要检查一下下面的选项:

        <a href="options.html#'shell'">'shell'</a>         指定 Vim 用于执行外部命令的外壳。
        <a href="options.html#'shellcmdflag'">'shellcmdflag'</a>  传给外壳的参数
        <a href="options.html#'shellquote'">'shellquote'</a>    外壳程序使用的引号 (用于引用命令)
        <a href="options.html#'shellxquote'">'shellxquote'</a>   用于命令和重定向文件名的引号
        <a href="options.html#'shelltype'">'shelltype'</a>     外壳程序的类型 (仅用于 Amiga)
        <a href="options.html#'shellslash'">'shellslash'</a>    在命令中使用正斜杠 (仅用于 MS-Windows 和相容系统)
        <a href="options.html#'shellredir'">'shellredir'</a>    用于把命令输出写入文件所使用的字符串

在 Unix 上，这几乎不是问题。因为总共只有两种外壳程序: "sh" 类的和 "csh" 类的。
Vim 会检查选项 <a href="options.html#'shell'">'shell'</a>，并根据它的类型自动设置这些参数。
   但在 MS-Windows 上，有很多不同的外壳程序，所以你必须修改这些外壳程序以便过
滤功能正常执行。详细情况请参考相应选项的帮助。


读 入 一 个 命 令 的 输 出

要把当前目录的内容读进文件，可以用如下命令:

Unix 上: 
<code class="example">        :read !ls</code>
MS-Windows 上: 
<code class="example">        :read !dir</code>
<code class="example"></code>
"ls" 或者 "dir" 的输出会被捕获并插入到光标下面。这好像读入一个文件一样，但是需
要加上一个 "!" 让 Vim 知道后面是一个命令。
    这些命令还可以带参数。而且前面还可以带一个范围用于告诉 Vim 把这行放在什么
地方:

<code class="example">        :0read !date -u</code>
<code class="example"></code>
这将用 UTC 格式把当前的时间插入到文件开头。(当然了，你的 date 命令必须能够接受
-u 选项。) <code class="note">注意</code> 这与 "!!date" 的区别: "!!date" 替代一行，而 ":read !date" 插入
一行。


把 文 本 输 出 到 一 个 命 令

Unix 命令 "wc" 用于统计单词数目。要统计当前文件有多少个单词，可以这样:

<code class="example">        :write !wc</code>
<code class="example"></code>
这和前面的写入命令一样，但文件名前面改为一个 "!" 用于告诉 Vim 后面是一个要被执
行的外部命令。被写入的文本将作为指定命令的标准输入。这个输出将是:

<code class="section">       4      47     249 </code>

"wc" 命令惜字如金。这表示你有 4 行，47 个单词和 249 个字符。

<code class="note">注意</code>不要错写成:

<code class="example">        :write! wc</code>
<code class="example"></code>
这会强制把当前文件存到当前目录的 "wc" 文件中。在这里空格的位置是非常重要的！


重 画 屏 幕

如果外部程序产生一个错误信息，屏幕显示就会乱掉。Vim 颇重效率，所以它只刷新那些
需要刷新的地方。可是它不可能知道其它程序修改了哪些地方。要强制 Vim 重画整个屏
幕:

<code class="example">        CTRL-L</code>
<code class="example"></code>
</section><hr class="doubleline" /><section class=inner>
<h4></h4>下一章:  <a href="usr_11.html#usr_11.txt">usr_11.txt</a>   从崩溃中恢复

版权: 参见  <a href="usr_01.html#manual-copyright">manual-copyright</a>   vim:tw=78:ts=8:noet:ft=help:norl:
</section>
</article>
<footer>
Generated by vim2html
</footer>
</body>
</html>
